home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Mac Magazin/MacEasy 32
/
Mac Magazin and MacEasy Magazine CD - Issue 32.iso
/
Grafik & Text
/
Fractal Trees
/
Sources etc
/
FractalTreeObject.cpp
< prev
Wrap
C/C++ Source or Header
|
1997-02-11
|
7KB
|
296 lines
#include <math.h>
#include <stdlib.h>
#include <time.h>
class FractalTree
{
// TYPE declarations
// The basic tree data type. consists of branch length, and angle
// and pointers to the children branches.
struct TreeType
{
float BranchLength; // Note this is relative length to 1.
// Actual length determined at draw time.
float BranchAngle; // in radians
TreeType *left;
TreeType *right;
};
enum SideType {left, right};
//****************************************************************************************
//****************************************************************************************
public:
// constructor
FractalTree(int UMaxHeight, float UBranchLengthModifier,
float UBranchAngleModifier, float ULengthRandFactor,
float UAngleRandFactor);
// creates a memory model of the tree
void GrowTree();
// draws the tree to the active window
void DrawTree();
//****************************************************************************************
//****************************************************************************************
private:
void RecurGrowTree (TreeType *Tree, float BranchLength, float BranchAngle, int curHeight);
void RecurDrawTree (TreeType *Tree, int x1, int y1, int Level);
int CalculateRootLength();
float ModifyBranchLength( float BranchLength );
float ModifyBranchAngle( float BranchAngle, SideType Side );
void DrawLine( short x1, short y1, short x2, short y2 );
float CalculateRandomValue( float RandomValue );
TreeType *Root; // a binary tree to store the Tree data.
int MaxHeight; // the maximum number of sequential branches to add.
float BranchLengthModifier;
float BranchAngleModifier;
float RootLength;
float LengthRandFactor;
float AngleRandFactor;
};
// ****************************************************************
// Constructor for FractalTree object.
FractalTree :: FractalTree(int UMaxHeight, float UBranchLengthModifier,
float UBranchAngleModifier, float ULengthRandFactor,
float UAngleRandFactor)
{
// Initialize the tree variables
MaxHeight = UMaxHeight;
BranchLengthModifier = UBranchLengthModifier;
BranchAngleModifier = UBranchAngleModifier;
LengthRandFactor = ULengthRandFactor;
AngleRandFactor = UAngleRandFactor;
// need this for later random calculations
srand( (unsigned int) time(0) );
}
// GrowTree
// Purpose: Calls RecurGrowTree with the data in the object.
void FractalTree :: GrowTree ()
{
Root = new TreeType;
RecurGrowTree(Root, 1, 3.1415926/2, 0 ); // that's π/2, or 90°.
}
// ****************************************************************
// RecurGrowTree for FractalTree object.
// Purpose: To grow a model of the tree in memory.
//
// PRE: The tree is stored in a binary tree, called Root,
// which already exists and is empty.
void FractalTree :: RecurGrowTree (TreeType *Tree, float BranchLength, float BranchAngle,
int curHeight)
{
// Variables
float NewBranchLengthLeft, NewBranchLengthRight;
float NewBranchAngleLeft, NewBranchAngleRight;
// put the given length and angle into the current branch.
Tree->BranchLength = BranchLength;
Tree->BranchAngle = BranchAngle;
// Recursively make the subbranches.
if (curHeight++ <= MaxHeight)
{
// prepare to make the children.
// Left child
Tree->left = new TreeType;
NewBranchLengthLeft = ModifyBranchLength( BranchLength );
NewBranchAngleLeft = ModifyBranchAngle( BranchAngle, left );
RecurGrowTree( Tree->left, NewBranchLengthLeft, NewBranchAngleLeft, curHeight );
// Right child
Tree->right = new TreeType;
NewBranchLengthRight = ModifyBranchLength( BranchLength );
NewBranchAngleRight = ModifyBranchAngle( BranchAngle, right );
RecurGrowTree( Tree->right, NewBranchLengthRight, NewBranchAngleRight, curHeight );
}
}
void FractalTree :: DrawTree ()
{
// Variables
int startx;
int starty;
startx = 390;
starty = 530;
RootLength = 120; // CalculateRootLength();
RecurDrawTree( Root, startx, starty, 0 );
}
void FractalTree :: RecurDrawTree (TreeType *Tree, int x1, int y1, int curHeight)
{
// Variables
float RealBranchLength;
// Calculate x2, y2:
RealBranchLength = RootLength * Tree->BranchLength;
int x2 = x1 + RealBranchLength * cos( Tree->BranchAngle );
int y2 = y1 - RealBranchLength * sin( Tree->BranchAngle );
// Draw the line
DrawLine( x1, y1, x2, y2 );
if (curHeight++ <= MaxHeight)
{
RecurDrawTree(Tree->left, x2, y2, curHeight);
RecurDrawTree(Tree->right, x2, y2, curHeight);
}
}
int FractalTree :: CalculateRootLength()
{
// Currently do not use width.
// Calculate the RootLength based on the BranchLengthModifier, the height
// of the window, and the maximum level of the tree.
// RootLength = Height / ( the sum of the rootlength^i for i = 1 to MaxHeight )
// This will yield a tree somewhat shorter than the window for all
// branch angle modifiers not zero.
int temp = 0;
for (int i = 1; i <= MaxHeight; i++)
{
temp += pow(BranchLengthModifier, i);
}
return 200 / temp; // ********* Need height of the current window!!!!
}
float FractalTree :: ModifyBranchLength( float BranchLength )
{
float RandomValue = 0;
float LengthAddedAtOneStdDev;
// First scale down the branch as required.
BranchLength = BranchLength * BranchLengthModifier;
// calculate the length which would be added to the branch
// at one standard deviation.
LengthAddedAtOneStdDev = LengthRandFactor * BranchLength;
// Calculate a random value between -100 and +100.
RandomValue = CalculateRandomValue(RandomValue);
// Adjust ratios so generated rand value matches with branch length
RandomValue = RandomValue * (LengthAddedAtOneStdDev/30);
// 30 is our arbitrary std. deviation ... we could calculate that better.
// adjust branch length
BranchLength = BranchLength + RandomValue;
// Based on BranchLengthModifier, return the new branch length.
// ie. return BranchLength * BranchLengthModifier.
return BranchLength;
}
float FractalTree :: CalculateRandomValue( float RandomValue )
{
float newRand;
RandomValue = 0;
// set random value to a number between 0 and 200
for (int i = 1; i <= 20; i++)
{
newRand = rand();
RandomValue = RandomValue + ( (newRand/32768) * 10 );
}
// set random value to -100 to 100 and return
return RandomValue - 100;
}
float FractalTree :: ModifyBranchAngle( float BranchAngle, SideType Side )
{
float RandomValue = 0;
float AngleAddedAtOneStdDev;
// Based on BranchAngleModifier return the new branch angle.
// If left, return BranchAngle + modifier
// If right, return BranchAngle - modifier.
// Left and right are determined with the branches rising from the
// top of the parent.
if (Side == left)
{
BranchAngle = BranchAngle + BranchAngleModifier;
}
else // Side = right
{
BranchAngle = BranchAngle - BranchAngleModifier;
}
AngleAddedAtOneStdDev = AngleRandFactor * BranchAngleModifier;
RandomValue = CalculateRandomValue(RandomValue);
RandomValue = RandomValue * AngleAddedAtOneStdDev / 20;
return BranchAngle + RandomValue;
}
// ****************************************************************
// DrawLine
void FractalTree :: DrawLine( short x1, short y1, short x2, short y2 )
{
MoveTo( x1, y1 );
LineTo( x2, y2 );
}